package server

import (
	"embed"
	"fmt"
	"net"

	serverGrpc "gitee.com/xgotool/sqlite-logs-more/app/server/grpc"
	"gitee.com/xgotool/sqlite-logs-more/app/server/web"
	"gitee.com/xgotool/sqlite-logs-more/protoc"
	"gitee.com/xgotool/sqlite-logs-more/service/rootdb"
	"gitee.com/xiaoyutab/xgotool/xgin"
	"gitee.com/xiaoyutab/xgotool/xgin/xginxgodb"
	"github.com/gin-gonic/gin"
	"google.golang.org/grpc"
)

// 开启WEB服务
func (c Config) webServer() {
	r := gin.Default()
	fmt.Println("开启WEB监听：", c.WEB)
	r.Use(xgin.Page, CORS)
	// 注册配置项的xgo路由
	xginxgodb.Regedit(r.Group("config"), nil)
	r.POST("dervice.info", xgin.Convert(web.DerviceInfo))            // 获取设备详情信息
	r.POST("dervice.info.set", xgin.Convert(web.DerviceInfoSet))     // 设置设备详情信息
	r.POST("dervice.info.hart", xgin.Convert(web.DerviceInfoHart))   // 设置心跳维持
	r.GET("dervice.list", xgin.Convert(web.DerviceList))             // 获取设备列表信息
	r.POST("log.pipe.create", xgin.Convert(web.LogPipeCreate))       // 记录Pipe日志信息
	r.POST("log.app.create", xgin.Convert(web.LogAppCreate))         // 记录app日志信息
	r.POST("log.runtime.create", xgin.Convert(web.LogRuntimeCreate)) // 记录runtime日志信息
	r.POST("log.quest.create", xgin.Convert(web.LogQuestCreate))     // 记录quest日志信息
	r.GET("log.pipe.args", xgin.Convert(web.LogPipeArgs))            // pipe日志的分组列表
	r.GET("log.app.args", xgin.Convert(web.LogAppArgs))              // app日志的分组列表
	r.GET("log.app.level", xgin.Convert(web.LogAppLevel))            // app日志的Level分组列表
	r.GET("log.quest.args", xgin.Convert(web.LogQuestArgs))          // quest日志的分组列表
	r.GET("log.runtime.args", xgin.Convert(web.LogRuntimeArgs))      // runtime日志的分组列表
	r.GET("log.pipe.list", xgin.Convert(web.LogPipeList))            // pipe日志列表信息
	r.GET("log.app.list", xgin.Convert(web.LogAppList))              // app日志列表信息
	r.GET("log.runtime.list", xgin.Convert(web.LogRuntimeList))      // runtime日志列表信息
	r.GET("log.quest.list", xgin.Convert(web.LogQuestList))          // quest日志列表信息
	r.POST("search.log", xgin.Convert(web.SearchLog))                // 搜索日志信息
	r.GET("search.log.info", xgin.Convert(web.SearchLogInfo))        // 搜素日志的上下1分钟的详情记录
	r.GET("files", xgin.Convert(web.Files))                          // 获取日志文件列表
	r.GET("file.7z", xgin.Convert(web.File7z))                       // 文件压缩
	r.GET("file.delete", xgin.Convert(web.FileDelete))               // 文件删除
	r.GET("file.download", xgin.Convert(web.FileDownload))           // 文件下载
	r.GET("dervice.app.list", xgin.Convert(web.DerviceAppList))      // 获取设备对应的APP列表
	// 路由注册完成
	err := r.Run(c.WEB)
	if err != nil {
		fmt.Println("开启WEB监听失败：", c.WEB, err)
	}
}

// 开启GRPC服务
func (c Config) grpcServer() {
	// 端口监听
	listen, err := net.Listen("tcp", c.GRPC)
	if err != nil {
		fmt.Println("开启GRPC监听失败：", err)
		return
	}
	defer listen.Close()
	// 服务启用
	opts := []grpc.ServerOption{
		grpc.ChainUnaryInterceptor(grpcRecoveryInterceptor, grpcAuthInterceptor, grpcLoggerInterceptor), // 普通请求拦截
	}
	grpcServer := grpc.NewServer(opts...)
	// 注册服务
	protoc.RegisterRemoteServer(grpcServer, &serverGrpc.GrpcRemote{})
	fmt.Println("开启GRPC监听：", c.GRPC)
	// 启动服务
	err = grpcServer.Serve(listen)
	if err != nil {
		fmt.Println("开启GRPC服务失败：", err)
	}
}

// 启动监听/运行
func (c Config) Linten() {
	gin.SetMode(gin.ReleaseMode)
	if c.RootPath == "" {
		panic("root库位置为空")
	}
	if c.WEB == "" && c.GRPC == "" {
		panic("web/grpc必须要监听一个")
	}
	ch := make(chan int, 1)
	rootdb.Regedit(&rootdb.Config{
		RootPath: _default.RootPath,
	})
	_, err := rootdb.Connect()
	if err != nil {
		panic(err)
	}
	xgin.Regedit(&xgin.Config{
		RequestKey: "data",
	})
	if c.WEB != "" {
		// 监听WEB服务的话，开启WEB端口
		go c.webServer()
	}
	if c.GRPC != "" {
		// 开启GRPC端口监听
		go c.grpcServer()
	}
	<-ch
}

// 配置项信息
type Config struct {
	FS       *embed.FS // files目录下的文件
	WEB      string    // WEB监听
	GRPC     string    // GRPC监听
	RootPath string    // root.db路径
}

var _default Config = Config{}

// 配置项注入
func Regedit(c *Config) *Config {
	if c == nil {
		return &_default
	}
	if c.WEB != "" {
		_default.WEB = c.WEB
	}
	if c.GRPC != "" {
		_default.GRPC = c.GRPC
	}
	if c.RootPath != "" {
		_default.RootPath = c.RootPath
	}
	return &_default
}
